#include <iostream>
using std::cout;
using std::endl;

template<class T>
class ObjectPool
{
  public:
    // 对象池默认构造函数
    ObjectPool()
      :_memory(nullptr)
      ,_remain(0)
      ,_freeList(nullptr)
    {}

    // 申请一块T类型的对象空间
    T* New()
    {
      T* obj = nullptr;
      // 1、先看自由链表中是否有可用的对象空间，有的话直接从哪里拿
      // 2、没有的话从对象池中申请一块
      if(_freeList)
      {
        void* next = *(void**)_freeList;
        obj = (T*)_freeList;
        _freeList = next;
      }
      else 
      {
        // 剩余空间不够一个对象的大小时要增容
        if(_remain < sizeof(T))
        {
          //delete[] _memory; // 错误操作
          size_t getSize = 100 * 1024;
          _memory = (char*)malloc(getSize);
          if(_memory == nullptr)
          {
            throw std::bad_alloc();
          }
          _remain = getSize;
        }
        // 确保容量足够分配出一块对象大小的内存空间
        obj = (T*)_memory;
        size_t blockSize = sizeof(T) < sizeof(void*)? sizeof(void*) : sizeof(T) ; 
        _memory += blockSize;
        _remain -= blockSize;
      }
      new(obj) T;// 定位new显示调用T类型的默认构造函数初始化内存空间
      return obj;
    }

    // 伪释放一块T类型的对象空间
    void Delete(T* obj)    
    {    
      //// 1、显示调用对象类型的构造函数，完成对象空间的内容清理
      //obj->~T();
      //// 2、把传入的这块对象空间头插到自由链表中
      //size_t addressLen = sizeof(int*);// 任意类型的指针变量都可以
      //if(addressLen == 4)
      //{
      //  *(int*)obj = _freeList;// 拿出obj前4个字节的内存
      //}
      //else 
      //{
      //  *(long long*)obj = _freeList;// 拿出obj前8个字节的内存
      //}
      //_freeList = obj;

      // 1、显示调用对象类型的构造函数，完成对象空间的内容清理
      obj->~T();    
      // 2、把传入的这块对象空间头插到自由链表中
      *(void**)obj = _freeList;    
      _freeList = obj;    
    }  

  private:
    char* _memory;  // 对象池：指向一块连续待申请的空间
    size_t _remain; // 记录对象池中剩余可用空间的大小，单位是字节
    void* _freeList;// 自由链表：指向第一块不用对象空间
};
